package com.main.tripplanner.algorithms.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.main.tripplanner.algorithms.DataRetrievalOpt;
import com.main.tripplanner.dao.AttractionDAO;
import com.main.tripplanner.persistent.Attraction;
import com.main.tripplanner.persistent.Attraction.AttractionType;
import com.main.tripplanner.persistent.City;
import com.main.tripplanner.persistent.Dosage;
import com.main.tripplanner.persistent.Route;
import com.main.tripplanner.service.AbstractService;

@Service
public class DataRetrievalOptImpl extends AbstractService implements DataRetrievalOpt{
	private static final int CONSTANT_BAR = 4;
	
	@Autowired
	private AttractionDAO attractionDAO;
	
	public Map<Attraction,Integer> nextAttractionEnjoymentQuestion(Route route, Attraction bestCandidate){
		List<Integer> attractionsIds = getEntityIds(route.getAttractions());
		List<Integer> citiesIds = getEntityIds(route.getCities());
		AttractionType attractionType = getDesiredAttractionTypeFromDosage(route.getDosage());
		List<Attraction> attractionsList = attractionDAO.getAllAttractionsByCountryAndType(route.getCountry(), citiesIds, attractionsIds, attractionType);
		Map<Attraction,Integer> attractionPotential = getMinimalPotentialAttraction(bestCandidate, attractionsList);
		return attractionPotential;
	}
	

	public City nextCityTimeQuestion(Attraction bestCandidate){
		return null;
	}

	private Map<Attraction, Integer> getMinimalPotentialAttraction(Attraction bestCandidate, List<Attraction> attractionsList) {
		Map<Attraction, Integer> resultMap = new HashMap<Attraction, Integer>();
		int minimalPotential = CONSTANT_BAR;
		Attraction minimalPotentialAttraction = null;
		for (Attraction attraction : attractionsList) {
			if(!attraction.equals(bestCandidate)){
				int potential = calculatePotential(attraction, bestCandidate);
				if(potential < CONSTANT_BAR && potential < minimalPotential){
					minimalPotential = potential;
					minimalPotentialAttraction = attraction;
				}
			}
		}
		if(minimalPotentialAttraction != null){
			resultMap.put(minimalPotentialAttraction, minimalPotential);
		}
		return resultMap;
	}
	
	private Integer calculatePotential(Attraction attraction, Attraction bestCandidateAttraction) {
		//if there are no votes, it means that a single vote with '10' will beat the best candidate.
		if(attraction.getEnjoymentLevelVotes() == 0){
			return 1;
		}
		//if the best candidate has top rate, we won't try to beat it.
		else if(bestCandidateAttraction.getEnjoymentLevel() == 10){
			return CONSTANT_BAR +1;
		}
		else{
			float cardinal = attraction.getEnjoymentLevelVotes() * (bestCandidateAttraction.getEnjoymentLevel() - attraction.getEnjoymentLevel());
			int result = (int) Math.ceil(cardinal / (10-bestCandidateAttraction.getEnjoymentLevel()));
			//if we have a tie (0) we'll break it by one more vote
			return (result <= 0) ? 1 : result;
		}
	}


	private AttractionType getDesiredAttractionTypeFromDosage(Dosage dosage) {
		AttractionType attractionType = null;
		float maxValue = 0;
		if(dosage.getCulturePercentage()> maxValue){
			attractionType = AttractionType.CULTURE;
			maxValue = dosage.getCulturePercentage();
		}
		if(dosage.getExtremePercentage() > maxValue){
			attractionType = AttractionType.EXTREME;
			maxValue = dosage.getExtremePercentage();
		}
		if(dosage.getFamilyPercentage() > maxValue){
			attractionType = AttractionType.FAMILY;
			maxValue = dosage.getFamilyPercentage();
		}
		if(dosage.getNightLifePercentage() > maxValue){
			attractionType = AttractionType.NIGHT_LIFE;
			maxValue = dosage.getNightLifePercentage();
		}
		if(dosage.getTrekkingPercentage() > maxValue){
			attractionType = AttractionType.TREKKING;
			maxValue = dosage.getTrekkingPercentage();
		}
		return attractionType;
	}
}
